﻿using System;
using EPiAbstractions.Community.Blog;
using EPiServer.Common;
using EPiServer.Common.Security;
using EPiServer.Community.Blog;
using JoelAbrahamsson.TestUtilities;
using Moq;
using StructureMap.AutoMocking;
using Xunit;

namespace JoelAbrahamsson.MetaWeblog.Tests
{
    public class AddPostTests : IUseFixture<BlogModuleFixture>
    {
        private Mock<MetaWeblogHandler> SetupMetaWeblogHandler(IBlogHandlerFacade blogHandlerFacade, bool validateUser)
        {
            MoqAutoMocker<MetaWeblogHandler> metaWebLogHandlerAutoMocker = new MoqAutoMocker<MetaWeblogHandler>();
            metaWebLogHandlerAutoMocker.Inject(blogHandlerFacade);
            metaWebLogHandlerAutoMocker.PartialMockTheClassUnderTest();
            Mock<MetaWeblogHandler> partiallyFakeMetaWeblogHandler = Mock.Get(metaWebLogHandlerAutoMocker.ClassUnderTest);
            IUser validatedUser = null;
            if (validateUser)
                validatedUser = new Mock<IUser>().Object;
            partiallyFakeMetaWeblogHandler.Setup(
                handler => handler.GetValidatedUser(It.IsAny<Blog>(), It.IsAny<string>(), It.IsAny<string>())).Returns(validatedUser);
            UserAuthor fakeUserAuthor = new Mock<UserAuthor>().Object;
            partiallyFakeMetaWeblogHandler.Setup(handler => handler.GetOrCreateUserAuthor(It.IsAny<IUser>())).Returns(fakeUserAuthor);
            Blog blog = new Mock<Blog>().Object;
            partiallyFakeMetaWeblogHandler.Setup(handler => handler.GetBlog(It.IsAny<string>())).Returns(blog);
            return partiallyFakeMetaWeblogHandler;
        }

        [Fact]
        public void GivenPost_AddPost_AddsNewPostToBlog()
        {
            Mock<Blog> fakeBlog = SetupFakeBlog();
            Mock<Entry> fakeEntry = SetupFakeEntry();
            Mock<IBlogHandlerFacade> fakeBlogHandlerFacade = SetupFakeBlogHandlerFacade(fakeEntry);
            MetaWeblogHandler metaWeblogHandler = SetupMetaWeblogHandler(fakeBlogHandlerFacade.Object, true).Object;
            Post post = CreateNewPost();

            string returnedID = metaWeblogHandler.AddPost(fakeBlog.Object.ID.ToString(), string.Empty, string.Empty, post, true);

            fakeBlogHandlerFacade.Verify(facade => facade.AddEntry(It.Is<Entry>(entry => entry.Title == post.title)));
            fakeBlogHandlerFacade.Verify(facade => facade.AddEntry(It.Is<Entry>(entry => entry.Content == post.description)));
            Assert.Equal<string>(fakeEntry.Object.ID.ToString(), returnedID);
        }

        [Fact]
        public void GivenPost_AddPost_AddedPostHasCorrectAuthor()
        {
            Mock<Blog> fakeBlog = SetupFakeBlog();
            Mock<Entry> fakeEntry = SetupFakeEntry();
            Mock<IBlogHandlerFacade> fakeBlogHandlerFacade = SetupFakeBlogHandlerFacade(fakeEntry);
            Mock<MetaWeblogHandler> metaWeblogHandler = SetupMetaWeblogHandler(fakeBlogHandlerFacade.Object, true);
            UserAuthor expectedUserAuthor = new Mock<UserAuthor>().Object;
            metaWeblogHandler.Setup(handler => handler.GetOrCreateUserAuthor(It.IsAny<IUser>())).Returns(expectedUserAuthor);
            Post post = CreateNewPost();

            metaWeblogHandler.Object.AddPost(fakeBlog.Object.ID.ToString(), string.Empty, string.Empty, post, true);

            fakeBlogHandlerFacade.Verify(facade => facade.AddEntry(It.Is<Entry>(entry => entry.Author is UserAuthor)));
            fakeBlogHandlerFacade.Verify(facade => facade.AddEntry(It.Is<Entry>(entry => entry.Author == expectedUserAuthor)));
        }

        private Mock<Blog> SetupFakeBlog()
        {
            var fakeBlog = new Mock<Blog>();
            fakeBlog.Setup(blog => blog.ID).Returns(1);
            return fakeBlog;
        }

        private Mock<Entry> SetupFakeEntry()
        {
            var fakeEntry = new Mock<Entry>();
            fakeEntry.SetupGet(entry => entry.ID).Returns(1);
            return fakeEntry;
        }

        private Mock<IBlogHandlerFacade> SetupFakeBlogHandlerFacade(Mock<Entry> fakeEntry)
        {
            var fakeBlogHandlerFacade = new Mock<IBlogHandlerFacade>();
            fakeBlogHandlerFacade.Setup(facade => facade.AddEntry(It.IsAny<Entry>())).Returns(fakeEntry.Object);
            return fakeBlogHandlerFacade;
        }

        private Post CreateNewPost()
        {
            Post post = new Post();
            post.title = Guid.NewGuid().ToString();
            post.description = Guid.NewGuid().ToString();
            post.categories = new [] { RandomValues.String };
            return post;
        }

        [Fact]
        public void GivenPost_AddPost_SetsEntryProperties()
        {
            Mock<Blog> fakeBlog = SetupFakeBlog();
            Mock<Entry> fakeEntry = SetupFakeEntry();
            Mock<IBlogHandlerFacade> fakeBlogHandlerFacade = SetupFakeBlogHandlerFacade(fakeEntry);
            Mock<MetaWeblogHandler> metaWeblogHandler = SetupMetaWeblogHandler(fakeBlogHandlerFacade.Object, true);
            UserAuthor expectedUserAuthor = new Mock<UserAuthor>().Object;
            metaWeblogHandler.Setup(handler => handler.GetOrCreateUserAuthor(It.IsAny<IUser>())).Returns(expectedUserAuthor);
            Post post = CreateNewPost();

            metaWeblogHandler.Object.AddPost(fakeBlog.Object.ID.ToString(), string.Empty, string.Empty, post, true);

            metaWeblogHandler.Verify(handler => handler.SetEntryProperties(It.IsAny<Entry>(), It.IsAny<Post>(), It.IsAny<IAuthor>()));
        }

        public void SetFixture(BlogModuleFixture data)
        {
        }
    }
}
